package sheeps

import (
	"container/list"
	"syscall"
	"unsafe"
)

var sheeps_dll *syscall.LazyDLL

var abi_Log *syscall.LazyProc
var abi_Microsecond *syscall.LazyProc
var abi_UserActiveTimeOutStop *syscall.LazyProc

var abi_ConfigGetString *syscall.LazyProc
var abi_ConfigGetNumber *syscall.LazyProc
var abi_ConfigGetBool *syscall.LazyProc

var abi_SocketConnect *syscall.LazyProc
var abi_SocketSend *syscall.LazyProc
var abi_SocketClose *syscall.LazyProc

var abi_HsocketPeerAddr *syscall.LazyProc
var abi_HsocketLocalAddr *syscall.LazyProc
var abi_HsocketPeerAddrSet *syscall.LazyProc
var abi_GetHostByName *syscall.LazyProc

var abi_KcpCreate *syscall.LazyProc
var abi_KcpNodelay *syscall.LazyProc
var abi_KcpWndsize *syscall.LazyProc
var abi_KcpGetConv *syscall.LazyProc
var abi_KcpDebug *syscall.LazyProc

var abi_PlayStop *syscall.LazyProc
var abi_PlayPause *syscall.LazyProc
var abi_PlayNormal *syscall.LazyProc
var abi_PlayFast *syscall.LazyProc
var abi_PlayStep *syscall.LazyProc
var abi_PlayStepSession *syscall.LazyProc
var abi_PlayStepNote *syscall.LazyProc
var abi_PlayBack *syscall.LazyProc
var abi_PlayAction *syscall.LazyProc
var abi_PlayNoStop *syscall.LazyProc
var abi_PlayOver *syscall.LazyProc

var abi_ReportOnline *syscall.LazyProc
var abi_ReportOffline *syscall.LazyProc
var abi_ReportCounter *syscall.LazyProc
var abi_ReportApiResponse *syscall.LazyProc
var abi_ReportApiSend *syscall.LazyProc
var abi_ReportApiRecv *syscall.LazyProc
var abi_ReportOverMessage *syscall.LazyProc

type TaskConfig struct {
	Task_id    int
	Project_id int
	Machine_id int
	Run_number int
	Parms      string
	user_list  *list.List
}

type BaseUserCall interface {
	set_handle(handle uintptr)
	EventStart(taskcfg *TaskConfig, user_number int)
	EventConnectOpen(ip string, port int, protocol int)
	EventConnectMade(hsock uintptr)
	EventConnectFailed(hsock uintptr, errno int)
	EventConnectSend(ip string, port int, data []byte, protocol int)
	EventConnectRecved(hsock uintptr, data []byte)
	EventConnectClose(ip string, port int, protocol int)
	EventConnectClosed(hsock uintptr, errno int)
	EventTimeOut()
	EventStop(errmsg string)
}

type BaseUser struct {
	user_handle uintptr
}

func (B *BaseUser) set_handle(handle uintptr) {
	B.user_handle = handle
}

func (B *BaseUser) Log(log_level int, msg string) {
	b_msg, _ := syscall.BytePtrFromString(msg)
	abi_Log.Call(B.user_handle, uintptr(log_level), uintptr(unsafe.Pointer(b_msg)))
}

func (B *BaseUser) Microsecond() int64 {
	ret, _, _ := abi_Microsecond.Call()
	return int64(ret)
}

func (B *BaseUser) UserActiveTimeOutStop(time int){
	abi_UserActiveTimeOutStop.Call(B.user_handle, uintptr(time))
}

func (B *BaseUser) ConfigGetString(section string, key string, def string) string {
	s_section, _ := syscall.BytePtrFromString(section)
	s_key, _ := syscall.BytePtrFromString(key)
	value, _, _ := abi_ConfigGetString.Call(uintptr(unsafe.Pointer(s_section)), uintptr(unsafe.Pointer(s_key)), 0)
	if value == 0 {
		return def
	}
	return uintptr_2_string(value)
}

func (B *BaseUser) ConfigGetNumber(section string, key string, def int) int {
	s_section, _ := syscall.BytePtrFromString(section)
	s_key, _ := syscall.BytePtrFromString(key)
	value, _, _ := abi_ConfigGetNumber.Call(uintptr(unsafe.Pointer(s_section)), uintptr(unsafe.Pointer(s_key)), uintptr(def))
	return int(value)
}

func (B *BaseUser) ConfigGetBool(section string, key string, def bool) bool {
	s_section, _ := syscall.BytePtrFromString(section)
	s_key, _ := syscall.BytePtrFromString(key)
	def_value := 0
	if def {
		def_value = 1
	}
	value, _, _ := abi_ConfigGetBool.Call(uintptr(unsafe.Pointer(s_section)), uintptr(unsafe.Pointer(s_key)), uintptr(def_value))
	return value != 0
}

func (B *BaseUser) SocketConnect(ip string, port int, protocol int) uintptr {
	s_ip, _ := syscall.BytePtrFromString(ip)
	ret, _, _ := abi_SocketConnect.Call(B.user_handle, uintptr(unsafe.Pointer(s_ip)), uintptr(port), uintptr(protocol))
	return ret
}

func (B *BaseUser) SocketSend(hsock uintptr, data []byte, len int) {
	abi_SocketSend.Call(B.user_handle, hsock, uintptr(unsafe.Pointer(&data[0])), uintptr(len))
}

func (B *BaseUser) SocketClose(hsock uintptr) {
	abi_SocketClose.Call(B.user_handle, hsock)
}

func (B *BaseUser) SocketPeerAddrGet(hsock uintptr) (string, int) {
	bip := make([]byte, 40)
	var port int32 = 0
	abi_HsocketPeerAddr.Call(hsock, uintptr(unsafe.Pointer(&bip[0])), 40, uintptr(unsafe.Pointer(&port)))
	return cstring(bip), int(port)
}

func (B *BaseUser) SocketLocalAddrGet(hsock uintptr) (string, int) {
	bip := make([]byte, 40)
	var port int32 = 0
	abi_HsocketLocalAddr.Call(hsock, uintptr(unsafe.Pointer(&bip[0])), 40, uintptr(unsafe.Pointer(&port)))
	return cstring(bip), int(port)
}

func (B *BaseUser) SocketPeerAddrSet(hsock uintptr, ip string, port int) {
	s_ip, _ := syscall.BytePtrFromString(ip)
	abi_HsocketPeerAddrSet.Call(hsock, uintptr(unsafe.Pointer(s_ip)), uintptr(port))
}

func (B *BaseUser) GetHostByName(name string) string {
	s_name, _ := syscall.BytePtrFromString(name)
	ip := make([]byte, 40)
	abi_GetHostByName.Call(uintptr(unsafe.Pointer(s_name)), uintptr(unsafe.Pointer(&ip[0])), 40)
	return string(ip)
}

func (B *BaseUser) KcpCreate(hsock uintptr, conv int, stream int) {
	abi_KcpCreate.Call(hsock, uintptr(conv), uintptr(stream))
}

func (B *BaseUser) KcpNodelay(hsock uintptr, nodelay int, interval int, resend int, nc int) {
	abi_KcpNodelay.Call(hsock, uintptr(nodelay), uintptr(interval), uintptr(resend), uintptr(nc))
}

func (B *BaseUser) KcpWndsize(hsock uintptr, snwd int, rcwn int) {
	abi_KcpWndsize.Call(hsock, uintptr(snwd), uintptr(rcwn))
}

func (B *BaseUser) KcpGetconv(hsock uintptr) int {
	conv, _, _ := abi_KcpGetConv.Call(hsock)
	return int(conv)
}

func (B *BaseUser) KcpDebug(hsock uintptr) string {
	debug := make([]byte, 256)
	abi_KcpDebug.Call(hsock, uintptr(unsafe.Pointer(&debug[0])), 256)
	return cstring(debug)
}

func (B *BaseUser) PlayStop(err string) {
	err_msg, _ := syscall.BytePtrFromString(err)
	abi_PlayStop.Call(B.user_handle, uintptr(unsafe.Pointer(err_msg)))
}

func (B *BaseUser) PlayNoraml() {
	abi_PlayNormal.Call(B.user_handle)
}

func (B *BaseUser) PlayPause() {
	abi_PlayPause.Call(B.user_handle)
}

func (B *BaseUser) PlayFast(fast bool) {
	flag := 0
	if fast {
		flag = 1
	}
	abi_PlayFast.Call(B.user_handle, uintptr(flag))
}

func (B *BaseUser) PlayStep() int {
	step, _, _ := abi_PlayStep.Call(B.user_handle)
	return int(step)
}

func (B *BaseUser) PlayStepSession() int {
	key, _, _ := abi_PlayStepSession.Call(B.user_handle)
	return int(key)
}

func (B *BaseUser) PlayStepNote() string {
	note, _, _ := abi_PlayStepNote.Call(B.user_handle)
	return uintptr_2_string(note)
}

func (B *BaseUser) PlayBack(step int) {
	abi_PlayBack.Call(B.user_handle, uintptr(step))
}

func (B *BaseUser) PlayAction(action int) {
	abi_PlayAction.Call(B.user_handle, uintptr(action))
}

func (B *BaseUser) PlayNoStop() {
	abi_PlayNoStop.Call(B.user_handle)
}

func (B *BaseUser) PlayOver() bool {
	over, _, _ := abi_PlayOver.Call(B.user_handle)
	return over != 0
}

func (B *BaseUser) ReportOnline() {
	abi_ReportOnline.Call(B.user_handle)
}

func (B *BaseUser) ReportOffline() {
	abi_ReportOffline.Call(B.user_handle)
}

func (B *BaseUser) ReportCounter(key string, value int, report_type int, space_time int) {
	s_key, _ := syscall.BytePtrFromString(key)
	abi_ReportCounter.Call(B.user_handle, uintptr(unsafe.Pointer(s_key)), uintptr(value), uintptr(report_type), uintptr(space_time))
}

func (B *BaseUser) ReportAPIResponse(api string, response_time int) {
	s_api, _ := syscall.BytePtrFromString(api)
	abi_ReportApiResponse.Call(B.user_handle, uintptr(unsafe.Pointer(s_api)), uintptr(response_time))
}

func (B *BaseUser) ReportAPISend(api string, flow int, count int) {
	s_api, _ := syscall.BytePtrFromString(api)
	abi_ReportApiSend.Call(B.user_handle, uintptr(unsafe.Pointer(s_api)), uintptr(flow), uintptr(count))
}

func (B *BaseUser) ReportAPIRecv(api string, flow int, count int) {
	s_api, _ := syscall.BytePtrFromString(api)
	abi_ReportApiRecv.Call(B.user_handle, uintptr(unsafe.Pointer(s_api)), uintptr(flow), uintptr(count))
}

func (B *BaseUser) ReportOverMessage(message string) {
	s_msg, _ := syscall.BytePtrFromString(message)
	abi_ReportOverMessage.Call(B.user_handle, uintptr(unsafe.Pointer(s_msg)))
}

func cstring(p []byte) string {
	for i := 0; i < len(p); i++ {
		if p[i] == 0 {
			return string(p[0:i])
		}
	}
	return string(p)
}

func uintptr_2_string(ptr uintptr) string {
	data := make([]byte, 0)
	p := (*byte)(unsafe.Pointer(ptr))
	for *p != 0 {
		data = append(data, *p)
		ptr++
		p = (*byte)(unsafe.Pointer(ptr))
	}
	return string(data)
}

func uintptr_2_bytes(ptr uintptr, len int) []byte {
	data := make([]byte, len)
	var p *byte
	for i := 0; i < len; i++ {
		p = (*byte)(unsafe.Pointer(ptr))
		data[i] = *p
		ptr++
	}
	return data
}

//callback 必须要有返回值，不然会报错

func event_start_callback(U *BaseUserCall, task_id int32, user_number int32) int {
	(*U).EventStart(task_all[int(task_id)], int(user_number))
	return 0
}

func event_connect_open_callback(U *BaseUserCall, ip uintptr, port int32, protocol int8) int {
	g_ip := uintptr_2_string(ip)
	(*U).EventConnectOpen(g_ip, int(port), int(protocol))
	return 0
}

func event_connect_made_callback(U *BaseUserCall, hsock uintptr) int {
	(*U).EventConnectMade(hsock)
	return 0
}

func event_connect_failed_callback(U *BaseUserCall, hsock uintptr, errno int32) int {
	(*U).EventConnectFailed(hsock, int(errno))
	return 0
}

func event_connect_send_callback(U *BaseUserCall, ip uintptr, port int32, data uintptr, len int32, protocol int8) int {
	g_ip := uintptr_2_string(ip)
	g_data := uintptr_2_bytes(data, int(len))
	(*U).EventConnectSend(g_ip, int(port), g_data, int(protocol))
	return 0
}

func event_connect_recved_callback(U *BaseUserCall, hsock uintptr, data uintptr, len int32) int {
	g_data := uintptr_2_bytes(data, int(len))
	(*U).EventConnectRecved(hsock, g_data)
	return 0
}

func event_connect_close_callback(U *BaseUserCall, ip uintptr, port int32, protocol int8) int {
	g_ip := uintptr_2_string(ip)
	(*U).EventConnectClose(g_ip, int(port), int(protocol))
	return 0
}

func event_connect_closed_callback(U *BaseUserCall, hsock uintptr, errno int32) int {
	(*U).EventConnectClosed(hsock, int(errno))
	return 0
}

func event_timeout_callback(U *BaseUserCall) int {
	(*U).EventTimeOut()
	return 0
}

func event_stop_callback(U *BaseUserCall, errmsg uintptr) int {
	err := uintptr_2_string(errmsg)
	(*U).EventStop(err)
	return 0
}

func init_sheeps_api() {
	abi_Log = sheeps_dll.NewProc("TaskUserLog")
	abi_Microsecond = sheeps_dll.NewProc("Microsecond")
	abi_UserActiveTimeOutStop = sheeps_dll.NewProc("UserActiveTimeOutStop")

	abi_ConfigGetString = sheeps_dll.NewProc("config_get_string_value")
	abi_ConfigGetNumber = sheeps_dll.NewProc("config_get_int_value")
	abi_ConfigGetBool = sheeps_dll.NewProc("config_get_bool_value")

	abi_SocketConnect = sheeps_dll.NewProc("SocketConnect")
	abi_SocketSend = sheeps_dll.NewProc("SocketSend")
	abi_SocketClose = sheeps_dll.NewProc("SocketClose")

	abi_HsocketPeerAddr = sheeps_dll.NewProc("HsocketPeerAddr")
	abi_HsocketLocalAddr = sheeps_dll.NewProc("HsocketLocalAddr")
	abi_HsocketPeerAddrSet = sheeps_dll.NewProc("HsocketPeerAddrSet")
	abi_GetHostByName = sheeps_dll.NewProc("GetHostByName")

	abi_KcpCreate = sheeps_dll.NewProc("HsocketKcpCreate")
	abi_KcpNodelay = sheeps_dll.NewProc("HsocketKcpNodelay")
	abi_KcpWndsize = sheeps_dll.NewProc("HsocketKcpWndsize")
	abi_KcpGetConv = sheeps_dll.NewProc("HsocketKcpGetConv")
	abi_KcpDebug = sheeps_dll.NewProc("HsocketKcpDebug")

	abi_PlayStop = sheeps_dll.NewProc("PlayStop")
	abi_PlayPause = sheeps_dll.NewProc("PlayPause")
	abi_PlayNormal = sheeps_dll.NewProc("PlayNormal")
	abi_PlayFast = sheeps_dll.NewProc("PlayFast")
	abi_PlayAction = sheeps_dll.NewProc("PlayAction")
	abi_PlayStep = sheeps_dll.NewProc("PlayStep")
	abi_PlayStepSession = sheeps_dll.NewProc("PlayStepSession")
	abi_PlayStepNote = sheeps_dll.NewProc("PlayStepNote")
	abi_PlayBack = sheeps_dll.NewProc("PlayBack")
	abi_PlayNoStop = sheeps_dll.NewProc("PlayNoStop")
	abi_PlayOver = sheeps_dll.NewProc("PlayOver")

	abi_ReportOnline = sheeps_dll.NewProc("ReportOnline")
	abi_ReportOffline = sheeps_dll.NewProc("ReportOffline")
	abi_ReportCounter = sheeps_dll.NewProc("ReportCounter")
	abi_ReportApiResponse = sheeps_dll.NewProc("ReportApiResponse")
	abi_ReportApiSend = sheeps_dll.NewProc("ReportApiSend")
	abi_ReportApiRecv = sheeps_dll.NewProc("ReportApiRecv")
	abi_ReportOverMessage = sheeps_dll.NewProc("ReportOverMessage")

}

func init_user_event_callback() {
	start := syscall.NewCallback(event_start_callback)
	open := syscall.NewCallback(event_connect_open_callback)
	made := syscall.NewCallback(event_connect_made_callback)
	fail := syscall.NewCallback(event_connect_failed_callback)
	send := syscall.NewCallback(event_connect_send_callback)
	recv := syscall.NewCallback(event_connect_recved_callback)
	close := syscall.NewCallback(event_connect_close_callback)
	closed := syscall.NewCallback(event_connect_closed_callback)
	timeout := syscall.NewCallback(event_timeout_callback)
	stop := syscall.NewCallback(event_stop_callback)
	set_user_callback := sheeps_dll.NewProc("set_user_event_callback")
	set_user_callback.Call(start, open, made, fail, send, recv, close, closed, timeout, stop)
}

var task_all = make(map[int]*TaskConfig, 256)

var task_start_callback_func func(*TaskConfig)
var task_stop_callback_func func(*TaskConfig)
var create_user_callback_func func(uintptr) BaseUserCall

func task_start_callback(task_id int32, project_id int32, machine_id int32, run_number int32, parms uintptr) int {
	taskcfg := new(TaskConfig)
	taskcfg.Task_id = int(task_id)
	taskcfg.Project_id = int(project_id)
	taskcfg.Machine_id = int(machine_id)
	taskcfg.Run_number = int(run_number)
	taskcfg.Parms = uintptr_2_string(parms)
	taskcfg.user_list = list.New()
	task_all[int(task_id)] = taskcfg
	if task_start_callback_func != nil {
		task_start_callback_func(taskcfg)
	}
	return 0
}

func task_stop_callback(task_id int32) int {
	if task_stop_callback_func != nil {
		task_stop_callback_func(task_all[int(task_id)])
	}
	delete(task_all, int(task_id))
	return 0
}

func task_user_create(user_handle uintptr, task_id int32) uintptr {
	user := create_user_callback_func(user_handle)
	user.set_handle(user_handle)
	ptr := &user
	task_all[int(task_id)].user_list.PushBack(ptr)
	return uintptr(unsafe.Pointer(ptr))
}

func init_task_callback() {
	create := syscall.NewCallback(task_user_create)
	start := syscall.NewCallback(task_start_callback)
	stop := syscall.NewCallback(task_stop_callback)
	set_task_callback := sheeps_dll.NewProc("set_task_callback")
	set_task_callback.Call(create, start, stop)
}

func init_engin(create_user func(uintptr) BaseUserCall, task_start func(*TaskConfig), task_stop func(*TaskConfig)) {
	create_user_callback_func = create_user
	task_start_callback_func = task_start
	task_stop_callback_func = task_stop
	sheeps_dll = syscall.NewLazyDLL("Sheeps.dll")
	init_sheeps_api()
	init_user_event_callback()
	init_task_callback()
}

func start_engin(project_id int, group_id int, local_server bool, config_file string) {
	run := sheeps_dll.NewProc("TaskManagerRunWithBridge")
	configfile, _ := syscall.BytePtrFromString(config_file)
	var server int = 0
	if local_server {
		server = 1
	}
	run.Call(uintptr(project_id), uintptr(group_id), uintptr(server), uintptr(unsafe.Pointer(configfile)))
}

func LoadEngin(project_id int, group_id int, local_server bool, config_file string, create_user func(uintptr) BaseUserCall) {
	//func LoadEngin(project_id int, group_id int, local_server bool, config_file string, create_user func(uintptr) BaseUserCall, task_start func(*TaskConfig), task_stop func(*TaskConfig)) {
	init_engin(create_user, nil, nil)
	start_engin(project_id, group_id, local_server, config_file)
}
